package com.entrogy.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.entrogy.bean.*;
import com.entrogy.service.*;
import com.entrogy.timing.ChangePersonTimeThread;
import com.entrogy.utils.TimeUtils;
import com.entrogy.utils.constants.Constants;
import com.entrogy.utils.constants.ErrorEnum;
import com.github.pagehelper.PageHelper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @ClassName DormController
 * @Description
 * @Author luoxingjiang
 * @Date 2019/7/9 0009 下午 2:56
 * @Version 1.0
 **/
@RestController
@RequestMapping(value = "/dorm")
@Api(description = "宿舍管理接口")
public class DormController {

    private static final Logger logger = LoggerFactory.getLogger(DormController.class);

    @Autowired
    private DormService dormService;

    @Autowired
    private UserService userService;

    @Autowired
    private ClassService classService;

    @Autowired
    private PositionService positionService;

    @Autowired
    private StudentService studentService;

    @Autowired
    private SchoolService schoolService;


    @Value("${show.image.url}")
    private String showImage;



    @GetMapping(value = "/list")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "dormName", value = "宿舍名字", dataType = "String", paramType = "query"),
    })
    @ApiOperation(value = "查询宿舍")
    public Msg getDormList(String dormName) {
        Integer schoolCode = (Integer) SecurityUtils.getSubject().getSession().getAttribute("schoolCode");
        List<DormEntity> dormList = dormService.listDorm(schoolCode, null, dormName);
        return Msg.success().add("dormList", dormList);
    }

    @PostMapping(value = "/insert")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "dormName", value = "宿舍名字", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "floorNumber", value = "宿舍楼层数", dataType = "Integer", paramType = "query"),
    })
    @ApiOperation(value = "为当前学校新增宿舍")
    public Msg insertDorm(@ModelAttribute DormEntity dorm) {
        Integer schoolCode = (Integer) SecurityUtils.getSubject().getSession().getAttribute("schoolCode");
        if (schoolCode == null) {
            return Msg.fail(ErrorEnum.E_101, "对不起，登录已过期，请重新登录！");
        }
        //首先判断该校新增的宿舍名是否已存在
        List<String> dormNameList = dormService.listDormName(schoolCode);
        if (dormNameList.contains(dorm.getDormName())) {
            return Msg.fail(ErrorEnum.E_101, "对不起，该宿舍名已存在，请修改后重试！");
        }
        dorm.setSchoolCode(schoolCode);
        boolean result = dormService.insertDorm(dorm);
        if (result)
            return Msg.success();
        return Msg.fail(ErrorEnum.E_101, ErrorEnum.E_101.getErrorMsg());
    }

    @PutMapping(value = "/update")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "dormName", value = "新宿舍名字", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "id", value = "宿舍id", dataType = "Integer", paramType = "query"),
    })
    @ApiOperation(value = "修改宿舍名")
    public Msg updateDorm(@RequestBody DormEntity dorm) {
        boolean result = dormService.updateDorm(dorm);
        if (result)
            return Msg.success();
        return Msg.fail(ErrorEnum.E_101, ErrorEnum.E_101.getErrorMsg());
    }

    @DeleteMapping(value = "/delete")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "dormId", value = "宿舍id", dataType = "Integer", paramType = "query"),
    })
    @ApiOperation(value = "删除宿舍")
    public Msg deleteDorm(Integer dormId) {
        boolean result = dormService.deleteDorm(dormId);
        if (result)
            return Msg.success();
        return Msg.fail(ErrorEnum.E_101, ErrorEnum.E_101.getErrorMsg());
    }

    @PostMapping(value = "/assignStudents")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "floorId", value = "楼层id", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "studentIds", value = "学生的id数组", paramType = "query", dataType = "Integer"),
            @ApiImplicitParam(name = "gradeId", value = "年级id", paramType = "query", dataType = "Integer"),
            @ApiImplicitParam(name = "classId", value = "班级id", paramType = "query", dataType = "Integer"),
    })
    @ApiOperation(value = "将某些学生分配到宿舍的楼层")
    public Msg assignStudents(Integer floorId, Integer[] studentIds, Integer gradeId, Integer classId) {
        Integer schoolCode = (Integer) SecurityUtils.getSubject().getSession().getAttribute("schoolCode");
        List<Integer> studentIdList = Arrays.asList(studentIds);
        boolean result = dormService.updateStudentFloor(floorId, studentIdList, gradeId, classId, schoolCode);
        if (result)
            return Msg.success();
        return Msg.fail(ErrorEnum.E_101, "当前分配的宿舍尚未分配设备，请联系管理员！");
    }

    @GetMapping(value = "/listFloorStudent")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "floorId", value = "楼层id", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "dormId", value = "宿舍id", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "currentPage", value = "当前页", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "每页显示条数", dataType = "Integer", paramType = "query"),
    })
    @ApiOperation(value = "查询该楼层的学生列表")
    public Msg listFloorStudent(Integer floorId, Integer currentPage, Integer pageSize, Integer dormId) {
        Integer totalCount = dormService.countFloorStudent(floorId, dormId);
        PageHelper.startPage(currentPage == null ? 1 : currentPage, pageSize == null ? 100 : pageSize);
        List<JSONObject> studentList = dormService.listFloorStudent(floorId, dormId);
        Integer totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1;
        return Msg.success().add("studentList", studentList).add("showImage", showImage).add("totalCount", totalCount).add("totalPage", totalPage);
    }

    @DeleteMapping(value = "/deleteStudents")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "floorId", value = "楼层id", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "studentIds", value = "学生的id数组", paramType = "query"),
    })
    @ApiOperation(value = "将某些学生从宿舍的楼层移除")
    public Msg deleteStudents(Integer floorId, Integer[] studentIds) {
        List<Integer> studentIdList = Arrays.asList(studentIds);
        boolean result = dormService.deleteStudentFromFloor(floorId, studentIdList);
        if (result)
            return Msg.success();
        return Msg.fail(ErrorEnum.E_101, ErrorEnum.E_101.getErrorMsg());
    }

    @PostMapping(value = "/assignDevices")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "deviceId", value = "设备id", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "dormId", value = "宿舍id", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "type", value = "指定为进出设备，1为进2为出", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "deviceName", value = "设备名字", dataType = "String", paramType = "query"),
    })
    @ApiOperation(value = "将设备分配到宿舍---超级管理员专用")
    public Msg assignDevices(Integer deviceId, Integer dormId, Integer type, String deviceName) {
        String inOrOut = "";
        if (type == 1) {
            inOrOut = "in";
        } else if (type == 2) {
            inOrOut = "out";
        }
        Map<String, Object> params = new HashMap<>();
        params.put("deviceId", deviceId);
        params.put("dormId", dormId);
        params.put("inOrOut", inOrOut);
        params.put("deviceName", deviceName);
        boolean result = dormService.assignDevices(params);
        if (result)
            return Msg.success();
        return Msg.fail(ErrorEnum.E_101, ErrorEnum.E_101.getErrorMsg());
    }

    @DeleteMapping(value = "/deleteDevices")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "params", value = "参数字符串：包含属性有dormId、deviceIds的数组，转换为json字符串传入,例如：{\"dormId\" : 1,\"deviceIds\": [813]}", dataType = "String", paramType = "query"),
    })
    @ApiOperation(value = "将设备从宿舍删除---超级管理员专用")
    public Msg deleteDevices(String params) {
        JSONObject paramsObject = JSONObject.parseObject(params);
        Integer dormId = paramsObject.getInteger("dormId");
        JSONArray jsonArray = paramsObject.getJSONArray("deviceIds");
        List<Integer> deviceIds = JSONObject.parseArray(jsonArray.toJSONString(), Integer.class);
        if (deviceIds.size() == 0) {
            return Msg.fail(ErrorEnum.E_101, "您没有选择任何闸机！");
        }
        boolean result = dormService.deleteDeviceByDeviceIds(dormId, deviceIds);
        if (result)
            return Msg.success();
        return Msg.fail(ErrorEnum.E_101, ErrorEnum.E_101.getErrorMsg());
    }

    @GetMapping(value = "/listLifeTeacher")
    @ApiOperation(value = "查找该校生活老师列表")
    public Msg getListLifeTeacher() {
        Integer schoolCode = (Integer) SecurityUtils.getSubject().getSession().getAttribute("schoolCode");
        List<LifeTeacherEntity> lifeTeacherList = dormService.getListLifeTeacher(schoolCode);
        return Msg.success().add("lifeTeacherList", lifeTeacherList);
    }

    @PostMapping(value = "/assignLifeTeacher")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "lifeTeacherId", value = "生活老师id", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "id", value = "楼层id", dataType = "Integer", paramType = "query"),
    })
    @ApiOperation(value = "为楼层分配生活老师")
    public Msg assignLifeTeacher(String lifeTeacherId, Integer id) {
        boolean result = dormService.updateFloorLifeTeacher(lifeTeacherId, id);
        if (result)
            return Msg.success();
        return Msg.fail(ErrorEnum.E_101, ErrorEnum.E_101.getErrorMsg());
    }

    @GetMapping(value = "/getBackTime")
    @ApiOperation(value = "显示学校所有年级的归寝时间")
    public Msg getBackTime() {
        Integer schoolCode = (Integer) SecurityUtils.getSubject().getSession().getAttribute("schoolCode");
        List<GradeEntity> gradeBackTimeList = dormService.listGradeBackTime(schoolCode);
        for (GradeEntity gradeEntity : gradeBackTimeList) {
            //若果年级没有设置归寝时间，设置一个归寝时段，它的年级id和schoolCode进行手动赋值，便于前端显示
            if (gradeEntity.getBackTimeFrame() == null) {
                BackTimeFrameEntity backTimeFrameEntity = new BackTimeFrameEntity();
                backTimeFrameEntity.setGradeId(gradeEntity.getClassId()).setSchoolCode(gradeEntity.getSchoolCode());
                gradeEntity.setBackTimeFrame(backTimeFrameEntity);
            }
        }
        return Msg.success().add("gradeBackTimeList", gradeBackTimeList);
    }

    @PutMapping(value = "/setBackTime")
    @ApiOperation(value = "设置某个年级的归寝时间，暂时只支持晚上的归寝考勤时间设置，也暂时只对宿舍的晚上进行考勤")
    public Msg setBackTime(@RequestBody List<UpdateBackTimeFrameEntity> updateBackTimeFrameList) {
        if (updateBackTimeFrameList.size() == 0) {
            return Msg.fail(ErrorEnum.E_101, "您没有做任何改动！");
        }
        boolean result = dormService.updateGradeBackTime(updateBackTimeFrameList);
        if (result)
            return Msg.success();
        return Msg.fail(ErrorEnum.E_101, ErrorEnum.E_101.getErrorMsg());
    }

    @PutMapping(value = "/listLateStudent")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "checkTime", value = "当前正在操作点名的时间", dataType = "Date", paramType = "query"),
            @ApiImplicitParam(name = "gradeId", value = "要点名的年级id", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "uid", value = "用户id", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "dormId", value = "要点名的宿舍id", dataType = "Integer", paramType = "query"),
    })
    @ApiOperation(value = "一键点名，未到达点名时间即未到达归寝结束时间时，生活老师不能点名")
    public Msg listLateStudent(@DateTimeFormat(pattern = "HH:mm:ss") Date checkTime, Integer gradeId, String uid, Integer dormId) {
        //国家法定节假日是不用考勤的，调用结果说明：正常工作日对应结果为 0, 法定节假日对应结果为 1, 节假日调休补班对应的结果为 2，休息日对应结果为 3
        //暂时只控制法定节假日不考勤，周末这种情况可以考勤
        Integer isHolidayResult = TimeUtils.isHoliday(new Date());
        if (isHolidayResult != null && isHolidayResult.equals(1)) {
            return Msg.fail(ErrorEnum.E_101, "对不起，今天是法定节假日不能考勤！");
        }
        Integer schoolCode = userService.getUserByUid(uid).getSchoolCode();
        // TODO 暂不控制每层生活老师只看自己所管楼层迟到学生的视图，因为分配学生的时候没有分配楼层暂时无法统计
        //将生活老师所在当前宿舍的某个年级的归寝时间查询出来，判断是否已到归寝时间，未到归寝时间的话，不能点名
        Date backTime = dormService.getBackTimeByLifeTeacherId(uid, gradeId);// TODO 暂未考虑一个生活老师管理两栋宿舍的楼层的情况
        if (backTime == null || backTime.after(checkTime)) {
            return Msg.fail(ErrorEnum.E_101, "对不起，该年级未到点名时间不能点名！");
        }
        List<AttendanceExceptionStudentEntity> lateStudentList = dormService.listLateStudent(schoolCode, uid, gradeId, dormId);
        //点名结束后在已点名记录内插入记录
        Date now = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String checkGradeTime = simpleDateFormat.format(now);
        boolean result = dormService.addGradeCheckedRecord(gradeId, schoolCode, dormId, checkGradeTime);
        return Msg.success().add("lateStudentList", lateStudentList);
    }

    @GetMapping(value = "/getSelectCondition")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uid", value = "用户id", dataType = "Integer", paramType = "query"),
    })
    @ApiOperation(value = "得到小程序用户可筛选的条件，" +
            "因为不同身份能看到的视图不一样，返回数据type为0表示显示生活老师视图，为1显示班主任，为2显示年级组长")
    public Msg getSelectCondition(String uid) {
        Integer schoolCode = userService.getSchoolCodeByUserId(uid);
        //是否是生活老师
        boolean isLifeTeacher = positionService.checkPosition(uid, 8);
        // 新版本不做权限限制
//        //是否是班主任
//        boolean isClassLeader = positionService.checkPosition(uid, 16);
//        //是否是年级组长
//        boolean isGradeLeader = positionService.checkPosition(uid, 15);
//        if (!isClassLeader && !isGradeLeader && !isLifeTeacher){
//            return Msg.fail(ErrorEnum.E_104, ErrorEnum.E_104.getErrorMsg());
//        }
        Msg msg = Msg.success();
        if (isLifeTeacher) {
            List<DormEntity> dormList = dormService.listDorm(schoolCode, uid, null);
            msg.add("dormList", dormList);
        }
        // 该用户是否仅仅是生活老师
        List<PositionEntity> positionList = positionService.listTeacherPosition(uid);
        if (!(positionList.size() == 1 && positionList.get(0).getSid() == 8)) {
            Map<String, Object> params = new HashMap<>();
            params.put("type", 1);
            params.put("parentId", 1);
            params.put("schoolCode", schoolCode);
            List<ClassEntity> classEntity = classService.getClassList(params);
            msg.add("classEntity", classEntity);
        }
        return msg;
    }

    @GetMapping(value = "/dormAttendance")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "dormId", value = "宿舍id", dataType = "Integer", paramType = "query", required = false),
            @ApiImplicitParam(name = "time", value = "查询的日期", dataType = "Date", paramType = "query", required = true),
            @ApiImplicitParam(name = "classId", value = "班级id", dataType = "Integer", paramType = "query", required = false),
            @ApiImplicitParam(name = "isNormal", value = "正常流水", dataType = "Integer", paramType = "query", required = false),//0为教师查询正常流水，1为教师查询异常流水
    })
    @ApiOperation(value = "宿舍考勤，通过小程序的uid判断是生活老师还是班主任显示不同的视图，年级主任和班主任显示视图一样，只是年级主任能够查看更多的班级")
    public Msg dormAttendance(Integer dormId, Integer classId, @DateTimeFormat(pattern = "yyyy-MM-dd") Date time, Integer isNormal) {
        if (dormId != null && classId != null)
            return Msg.fail(ErrorEnum.E_90003, ErrorEnum.E_90003.getErrorMsg());
        //传有dormId参数则为生活老师在查询数据，有classId则为班主任或者年级主任查询数据
        if (dormId != null) {
            //生活老师查看迟到学生列表
            List<AttendanceExceptionStudentEntity> listLateStudent = dormService.lifeTeacherDormAttendance(dormId, time);
            return Msg.success().add("listLateStudent", listLateStudent).add("type", 0);
        } else {
            //教师或者年级组长按班级查看迟到学生列表
            List<AttendanceExceptionStudentEntity> listLateStudent = dormService.teacherDormAttendance(classId, time);
            return Msg.success().add("listLateStudent", listLateStudent).add("type", 1);
        }
    }


    @GetMapping(value = "/listDormGrade")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "uid", value = "用户id", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "dormId", value = "生活老师当前选择的宿舍id", dataType = "Integer", paramType = "query"),
    })
    @ApiOperation(value = "小程序得到生活老师所在宿舍所住的年级用于一键点名")
    public Msg listDormGrade(String uid, Integer dormId) {
        List<GradeEntity> gradeList = dormService.listDormGradeByLifeTeacher(uid);
        Integer schoolCode = userService.getSchoolCodeByUserId(uid);
        Date now = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String checkTime = simpleDateFormat.format(now);
        //查询该宿舍的该年级今天是否已经点过名了
        for (GradeEntity gradeEntity : gradeList) {
            boolean isChecked = dormService.gradeIsChecked(gradeEntity.getClassId(), schoolCode, checkTime, dormId);
            if (isChecked) {
                gradeEntity.setChecked(1);
            } else {
                gradeEntity.setChecked(0);
            }
        }
        return Msg.success().add("gradeList", gradeList);
    }

    @PutMapping(value = "/add-dorm-door-device")
    @ApiOperation(value = "分配寝室大门设备")
    public Msg addDormDoorDevice(@RequestBody DormDoorDeviceEntity dormDoorDevice) {
        String userId = (String) SecurityUtils.getSubject().getSession().getAttribute("userId");
        Integer schoolCode = (Integer) SecurityUtils.getSubject().getSession().getAttribute("schoolCode");
        dormDoorDevice.setCreateUserId(userId).setSchoolCode(schoolCode);
        boolean result = dormService.insertDormDoorDevice(dormDoorDevice);
        if (result)
            return Msg.success();
        return Msg.fail(ErrorEnum.E_101, "对不起，新增失败，请联系管理员");
    }

    @DeleteMapping(value = "/delete-dorm-door-device")
    @ApiOperation(value = "删除寝室大门设备")
    public Msg deleteDormDoorDevice(Integer[] dormDoorDeviceIdList) {
        String userId = (String) SecurityUtils.getSubject().getSession().getAttribute("userId");
        for (Integer dormDoorDeviceId : dormDoorDeviceIdList) {
            Integer deleteStatus = 1;
            boolean result = dormService.deleteDormDoorDevice(userId, dormDoorDeviceId, deleteStatus);
        }
        return Msg.success();
    }

    @PutMapping(value = "/temp-back-dorm")
    @ApiOperation(value = "教师为学生设置临时归寝，设置后学生能打开进寝室的大门设备")
    public Msg tempBackDorm(@RequestBody List<TempBackDormEntity> backDormStudentList) {
        if (backDormStudentList.size() == 0){
            return Msg.fail(ErrorEnum.E_90003, ErrorEnum.E_90003.getErrorMsg());
        }
        Integer schoolCode = studentService.getStudentSchoolCode(backDormStudentList.get(0).getStudentId());
        SchoolThdidUrlEntity schoolThdidUrl = schoolService.getSchoolThdidUrlAndGroupInfo(schoolCode, Constants.THDID_AI06);
        if (schoolThdidUrl == null){
            return Msg.fail(ErrorEnum.E_90011, ErrorEnum.E_90011.getErrorMsg());
        }
        long passStartTime = backDormStudentList.get(0).getStartTime().getTime() / 1000;
        long passEndTime = backDormStudentList.get(0).getEndTime().getTime() / 1000;
        if (passStartTime > passEndTime){
            return Msg.fail(ErrorEnum.E_101, "对不起，设置失败，开始时间不能大于结束时间！");
        }
        for (TempBackDormEntity tempBackDormEntity : backDormStudentList) {
            StudentEntity studentEntity = studentService.getStudentById(tempBackDormEntity.getStudentId());
            if (studentEntity.getStudentThdid() == 0){
                // TODO 此处可能需要返回推送失败的学生列表
                logger.info("推送学生=>" + studentEntity.getStudentName() + "的临时归寝权限时该学生没有实义德id");
                continue;
            }
            // 查询进寝室的人脸识别设备
            String inOrOut = "in";
            if (!StringUtils.isNoneBlank(studentEntity.getDormitory())){
                // TODO 此处可能需要返回推送失败的学生列表
                logger.info("推送学生=>" + studentEntity.getStudentName() + "的临时归寝权限时该学生尚未分配宿舍！");
                continue;
            }
            List<DormDoorDeviceEntity> dormDoorDeviceList = dormService.listDormDoorDevice(Integer.valueOf(studentEntity.getDormitory()), inOrOut);
            StringBuilder deviceIds = new StringBuilder();
            for (DormDoorDeviceEntity dormDoorDeviceEntity : dormDoorDeviceList) {
                if (dormDoorDeviceEntity.getDeviceId() != null){
                    deviceIds.append(",").append(dormDoorDeviceEntity.getDeviceId());
                }
            }
            if (deviceIds.length() > 0){
                logger.info("开始推送学生=>" + studentEntity.getStudentName() + "的临时归寝权限");
                ChangePersonTimeThread changePersonTimeThread = new ChangePersonTimeThread(deviceIds.substring(1), studentEntity.getStudentThdid() + "", 1,
                        1, "全体all", 999999, passStartTime, passEndTime, "学生临时归寝权限推送", 0, schoolThdidUrl.getPathUrl(), schoolThdidUrl.getAccessToken());
                changePersonTimeThread.start();
            }else {
                // TODO 此处可能需要返回推送失败的学生列表
                logger.info("推送学生=>" + studentEntity.getStudentName() + "的临时归寝权限时该学生所在宿舍无设备！");
                continue;
            }
        }
        return Msg.success();
    }


}
